/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pop3server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author canal65
 */
public class popHandler implements Runnable {

    Socket socket=null;
    final int USER = 1;
    final int PASS = 2;
    final int QUIT = 3;
    final int STAT = 4;
    final int LIST = 5;
    final int RETR = 6;
    final int DELE = 7;
    final int NOOP = 8;
    final int RSET = 9;
    final int TOP = 10;
    final int UIDL = 11;
    final int ERROR = -1;
    private String state = "A";
    private boolean loop = true;
    private BufferedReader br;
    private PrintStream out;
    public popHandler(Socket s){
        this.socket=s;
    }

    public void run(){
        try {
            p("new Thread Created!");
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintStream(socket.getOutputStream()); // para sacar por el socket
            out.println("-OK pop3 Server Ready");
            while(loop){
                String[] line = this.getCommand(br.readLine());//lee el comando
                int i=0;
                if(!br.ready()){//si hay otra linea en el buffer el comando está malo
                    i = Integer.parseInt(line[0]); //devuelve un numero asociado al comando recibido
                }else{
                    i = -1;
                }
                switch (i) {
                    case 1:
                        this.user(line[1]);
                        p("user");
                        break;
                    case 2:
                        this.pass(line[1]);
                        p("pass");
                        break;
                    case 3:
                        this.quit();
                        p("quit");
                        break;
                    case 4:
                        this.stat();
                        p("stat");
                        break;
                    case 5:
                        this.list(line[1]);
                        p("list");
                        break;
                    case 6:
                        this.retr(line[1]);
                        p("retr");
                        break;
                    case 7:
                        this.dele(line[1]);
                        p("dele");
                        break;
                    case 8:
                        this.noop();
                        p("noop");
                        break;
                    case 9:
                        this.rset();
                        p("rset");
                        break;
                    case 10:
                        this.top(line[1],line[2]);
                        p("top");
                        break;
                    case 11:
                        this.uidl(line[1]);
                        p("uidl");
                        break;
                    default:
                        p("UNKNOWN COMMAND");
                        out.println("-ERR invalid command");
                        break;
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(popHandler.class.getName()).log(Level.SEVERE, null, ex);
        }


    }

    public void user(String user){
        setUser(user);
        out.println("+OK password required.");
        //supuestamente, aunque el usuario no exista siempre devuelve ok,
        //devuelve negativo si el mailbox no permite plaintext ¿?

    }
    public static void setUser(String user){
    //guardas el usuario
    }

    public void pass(String pass){
        boolean pwd = setPass(pass);
        out.println(pwd? "+OK logged in." : "-ERR invalid Password.");
        if(pwd) state = "T";

    }
    public static boolean setPass(String pass){
        //tambien la implementas vos, y aqui si me devolves si el password es correcto o no
        return true;
    }

    public void quit(){
        exit();
        out.println("+OK See you later!");
        state = "U";
        try {
            socket.close();
            loop = false;
        } catch (IOException ex) {
            Logger.getLogger(popHandler.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
    public static void exit(){
    //borras los mensajes marcados como borrados
    //si queres hacer otras cosas cuando se cierre el socket
    }
    public void stat(){
    out.println("+OK "+getStat());
    }
    public static String getStat(){
        //devolves un String con el numero de mensajes en el maildrop
        // y el tamaño del maildrop en bytes separados por un espacio
        //(Ej: "2 320")
        return "";
    }

    public void list(String message){
        int msg = message.equals("")? 0 :Integer.valueOf(message);
        out.println("+OK scan listing follows.");
        out.println(getList(msg));
        out.println(".");
    }
    public static String getList(int msg){
    // si msg es 0, devolves todos los scan listings*
    //si es diferente de 0 devolves el scan listing* del numero de mensaje
   /*
             *scan listing consists of the message-number of the
             message, followed by a single space and the exact size of
             the message in octets.
     */
     //cada listing en una linea nueva...
        return "";
    }

    
    public void retr(String message){
        int msg = Integer.valueOf(message);
        out.println(getMessage(msg).equals("ERROR")?"+OK "+ getMessageSize(msg)+ " octets follow":"-ERR no such message");
        out.println(".");
    }
    public static String getMessage(int msg){
        //devolves el correo completo con id = msg
        return "";
    }
    public static int getMessageSize(int msg){
        //devolves el tamaño del mensaje con id=msg en octetos(bytes)
        return 0;
    }

    public void dele(String msg){
        int m = Integer.valueOf(msg);
        int del = delete(m);
        out.println(del==1? "+OK message " + msg + "deleted" :
                    del==2? "-ERR message "+ msg + "already deleted":
                            "-ERR no such message");
    }
    public static int delete(int msg){
        //MARCAS el mensaje con id=msg como borrado
        //NO BORRAS el mensaje
        //devolves 1 si lo marcaste correctamente
        //2 si ya esta como marcado
        //cualquier otro numero si el mensaje no existe
        return 0;
    }
    
    public void noop(){
        out.println("+OK good for you!");
    }
    
    public void rset(){
        unmark();
        out.println("+OK messages unmarked");
    }
    public static void unmark(){
    //si hay mensajes marcados como borrados los desmarcas
        //si no hay no haces ni verga
    }
    
    public void top(String message, String nlines){
        int msg = Integer.valueOf(message);
        int lines = Integer.valueOf(nlines);
        String top = getTop(msg,lines);
        if(top.equals("ERROR")){
            out.println("-ERR no such message");
        }else{
            out.println("+OK top of message follows ");
            out.println(top);
            out.println(".");
        }
    
    }
    public static String getTop(int msg, int lines){
        //Si no existe el mensaje cuyo id = msg devolves "ERROR"
        //else devolves el numero de lineas del mensaje cuyo id=msg
        //el numero de lineas se refiere a las lineas del cuerpo del mensaje
        //el header lo devolves todo (header+lineas del mensaje)
        //si lines es mayor a las lineas del mensaje devolves todo el mensaje
        return "";
    }
          
    public void uidl(String message){
        
        int msg = message.equals("")? 0:
                  Integer.valueOf(message);
        String uidl = getUidl(msg);
        if(!uidl.equals("ERROR")){
            if(msg == 0){
                out.println("+OK unique-id listing follows");
                out.println(uidl);
                out.println(".");
            }else{
                out.println("+OK "+ uidl);
            }
        }else{
            out.println("-ERR no such message");
        }
        
    }      
    public static String getUidl(int msg){
        //si no existe el mensaje devolves "ERROR"
        //si msg=0 devolves los uidls de todos los mensajes finalizando con \n cada uidl
        //si msg!=0 devolves el uidl con id=msg
        //para saber que es uidl anda a http://www.ietf.org/rfc/rfc1939.txt y buscas el comando
        //yo no lo entiendo muy bien ^^
        return "";
    }
    
    public String[] getCommand(String line){
      String[] parts = line.toLowerCase().split(" ");
      
      int command = -1;
      if(state.equals("A")){
           command =
                      (2 < parts.length)? ERROR : //si hay más de 2 string es invalido
                      (parts[0].equals("user"))? USER ://el primer string tiene que ser igual a un comando valido
                      (parts[0].equals("pass"))? PASS :
                      (line.toLowerCase().equals("quit"))? QUIT :
                       ERROR;//si no es igual a ningun comando, es invalido
      }
      else if(state.equals("T")){
           command =  (parts[0].equals("uidl"))? UIDL:
                      (2 < parts.length)? ERROR : //si hay más de 2 string es invalido
                      (line.toLowerCase().equals("quit"))? QUIT :
                      (parts[0].equals("list"))? LIST :
                      (parts[0].equals("retr"))? RETR:
                      (parts[0].equals("dele"))? DELE:
                      (line.toLowerCase().equals("noop"))? NOOP:
                      (line.toLowerCase().equals("rset"))? RSET:
                      (parts[0].equals("top"))? TOP:
                       ERROR;//si no es igual a ningun comando, es invalido
      }else{command = -1;}
      String[] ret = new String[3];
      ret[0] = (new Integer(command)).toString();
      ret[1] = "";
      ret[2] = "";
      if(parts.length == 1){

      }
      else if(parts.length == 2){
      ret[1] = parts[1];
      }else if(parts.length == 3){
      ret[1] = parts[1];
      ret[2] = parts[2];
      }else{
      ret[0] = "-1";
      }
      return ret;
    }
    public static void p(Object o){
        System.out.println(o);
    }

}
